package com.physics.mps.module.util;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.physics.mps.common.util.AssertUtil;
import com.physics.mps.common.util.OkHttpUtil;
import com.physics.mps.entity.enums.CodeEnum;
import com.physics.mps.entity.vo.StartComputeVo;
import com.physics.mps.module.ansys.vo.AnsysSolveVo;
import com.physics.mps.module.ansys.vo.MeshVo;
import com.physics.mps.module.ansys.vo.PartVo;
import com.physics.mps.module.ansys.vo.SpaceClaimVo;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author mcsoft
 * @since 2023/11/6
 */
@Component
@Log4j2
public class AnsysJsonResolver {
    /**
     * 服务器ansys的stp存储目录
     */
    @Value("${simulate.ansys.stp-path}")
    private String stpDir;

    /**
     * 服务器ansys的scdoc存储目录
     */
    @Value("${simulate.ansys.sc-path}")
    private String scDir;

    /**
     * 服务器ansys的部件名存储目录
     */
    @Value("${simulate.ansys.model-name}")
    private String modelname;

    /**
     * 服务器ansys的工作目录
     */
    @Value("${simulate.ansys.work-path}")
    private String workDir;

    /**
     * 服务器ansys的结果存储目录
     */
    @Value("${simulate.ansys.work-path}")
    private String resultDir;

    /**
     * 前处理参数
     */
    private SpaceClaimVo spaceClaimVo;

    /**
     * 网格参数
     */
    private MeshVo meshVo;

    /**
     * 部件参数
     */
    private List<PartVo> partVos;

    /**
     * 材料名以及对应部件参数
     */
    private Map<String, PartVo> materials;

    /**
     * 部件名列表
     */
    private Set<String> partNames;

    /**
     * 默认材料参数
     */
    private String defaultMaterial;

    /**
     * 重力加速度方向
     */
    private String gravityDirection;

    /**
     * 外界温度
     */
    private String t0;

    /**
     * stp文件名
     */
    private String stpName;

    /**
     * 模型部件数量
     */
    private int partNum;

    /**
     * 共享拓扑公差
     */
    private String tolerance;

    /**
     * 并行核数
     */
    private String process;

    /**
     * 电路板部件名称
     */
    private String board;

    public AnsysJsonResolver() {
    }

    /**
     * 参数初始化
     */
    private void formattingResolver() {
        this.spaceClaimVo = new SpaceClaimVo();
        this.meshVo = new MeshVo();
        this.partVos = new ArrayList<>();
        this.materials = new HashMap<>();
        this.defaultMaterial = "";
        this.partNames = new HashSet<>();
        this.partNum = 0;
        this.t0 = "";
        this.tolerance = "";
        this.process = "";
        this.stpName = "";
        this.board = "";
    }

    /**
     * 接收参数，封装为计算参数对象AnsysSolveVo
     * @param startComputeVo 任务参数
     * @param jsonPath 参数json
     * @param type 参数种类
     * @return 传热参数
     */
    public AnsysSolveVo jsonParseToAnsysSolveVo(StartComputeVo startComputeVo, String jsonPath, Integer type) {
        //参数初始化
        formattingResolver();

        //生成参数map
        Map<String, Object> params;
        if (type == 1) {
            params = JSONUtil.toBean(jsonPath, LinkedHashMap.class);
        } else {
            params = jsonMap(jsonPath);
        }

        //解析参数
        params.forEach((name, value) -> {
            try {
                checkParamModule(name, value);
            } catch (Exception e) {
                log.info(String.format("Error Parameter: name=%s, value=%s", name, value));
            }
        });

        //将解析的参数封装为AnsysSolveVo
        AnsysSolveVo solveVo = new AnsysSolveVo();

        solveVo.setAppId(startComputeVo.getAppId());
        solveVo.setAppModuleId(startComputeVo.getAppModuleId());
        solveVo.setTaskId(IdUtil.fastSimpleUUID());
        solveVo.setTaskName(startComputeVo.getTaskName() + solveVo.getTaskId());

        spaceClaimVo.setStpPath(stpDir + stpName);
        spaceClaimVo.setScdocPath(scDir + solveVo.getTaskName() + ".scdoc");
        spaceClaimVo.setTxtPath(modelname + solveVo.getTaskName() + ".txt");
        spaceClaimVo.setTolerance(tolerance);
        spaceClaimVo.setStpName(stpName);
        solveVo.setSpaceClaimVo(spaceClaimVo);

        meshVo.setMeshPath(workDir + solveVo.getTaskName() + ".msh.gz");
        solveVo.setMeshVo(meshVo);
        solveVo.setPartNames(new HashMap<>());

//        if (partVos.size() < partNum) {
//            defaultMaterial();
//        }
        materials.forEach((name, value) -> {
            partVos.add(value);
        });
        solveVo.setPartVos(partVos);

        solveVo.setGravityDirection(gravityDirection);
        solveVo.setT0(t0);
        solveVo.setProcess(process);
        solveVo.setExportPath(resultDir);
        solveVo.setBoard(board);
        solveVo.setDefaultPartVo(materials.getOrDefault(defaultMaterial, null));
        return solveVo;
    }


    /**
     * 获取参数Map
     *
     * @param jsonPath 参数json
     * @return 参数map
     */
    private Map<String, Object> jsonMap(String jsonPath) {
        Map<String, Object> params = JSONUtil.readJSONObject(new File(jsonPath), StandardCharsets.UTF_8);
        return params;
    }

    /**
     * 读取参数，存储参数
     * @param name 属性名
     * @param value 属性值
     */
    private void checkParamModule(String name, Object value) {
        if (name.startsWith("ZPARAM_spaceclaim")) {
            storeSpaceClaim(name, value);
        } else if (name.startsWith("ZPARAM_material")) {
            storeMaterial(name, value);
        } else if (name.startsWith("mesh")) {
            storeMesh(name, value);
        } else if (name.startsWith("step")) {
            storeStep(name, value);
        } else if ("PATH_stpPath".equals(name)) {
//            String stpPath = String.valueOf(value);
//            String[] stpPathArr = stpPath.split("/");
//            stpName = stpPathArr[stpPathArr.length - 1];
//            //stpName = stpName.split("\\.")[0] + IdUtil.fastSimpleUUID() + ".stp";
//            String local = stpDir + stpName;
//            log.info("stpPath:" + stpPath);
//            log.info("local:" + local);
//            OkHttpUtil.download(stpPath, local);

            String downloadPath = String.valueOf(value);
            stpName = IdUtil.fastSimpleUUID() + ".stp";
            log.info("=== Ansys stp下载路径 {} === Ansys stp文件名 {}", downloadPath, stpName);
            String local = stpDir + stpName;
            OkHttpUtil.download(downloadPath, local);
        } else if ("partNum".equals(name)) {
            partNum = Integer.valueOf(String.valueOf(value));
        } else if (name.startsWith("other")) {
            if (name.endsWith("tolerance")) {
                tolerance = String.valueOf(value);
            }
            if (name.endsWith("process")) {
                this.process = String.valueOf(value);
            }
        } else if ("ZPARAM_BOARD_board1_partname".equals(name)) {
            board = String.valueOf(value);
        }
    }

    /**
     * 存储前处理参数
     * @param name 前处理参数名称——坐标
     * @param value 前处理参数坐标值
     */
    private void storeSpaceClaim(String name, Object value) {
        String[] s = name.split("_");
        if ("coordinate".equals(s[3])) {
            spaceClaimVo.getPartNames().add(s[4]);
            JSONArray arr = (JSONArray) value;
            spaceClaimVo.getCoordinates().add(new double[]{Double.valueOf((String) arr.get(0)) / 1000, Double.valueOf((String) arr.get(1)) / 1000, Double.valueOf((String) arr.get(2)) / 1000});
        }
    }

    /**
     * 存储材料参数
     * @param name 材料参数名称：部件名、网格尺寸、类型、密度、比热容、导热系数、能量
     * @param value 材料参数对应的值
     */
    private void storeMaterial(String name, Object value) {
        String[] s = name.split("_");
        PartVo partVo = materials.getOrDefault(s[2], new PartVo());
        switch (s[3]) {
            case "partname":
                partVo.setBodyname(String.valueOf(value));
                partNames.add(String.valueOf(value));
                break;
            case "boisize":
                partVo.setSize(String.valueOf(value));
                break;
            case "type":
                partVo.setType(String.valueOf(value));
                break;
            case "density":
                partVo.setDensity(String.valueOf(value));
                break;
            case "specificHeat":
                partVo.setSpecific_heat(String.valueOf(value));
                break;
            case "conductivity":
                partVo.setThermal_conductivity(String.valueOf(value));
                break;
            case "energy":
                partVo.setEnergy(String.valueOf(value));
                break;
            case "checkAllMesh":
                //赋予默认材料
                defaultMaterial = s[2];
                break;
        }
        materials.put(s[2], partVo);
    }

    /**
     * 存储网格参数
     * @param name 网格参数名称
     * @param value 网格参数值
     */
    private void storeMesh(String name, Object value) {
        if (name.endsWith("maxsize")) {
            meshVo.setMaxSize(String.valueOf(value));
        }
        if (name.endsWith("minsize")) {
            meshVo.setMinSize(String.valueOf(value));
        }
        if (name.endsWith("tolerance")) {
            tolerance = String.valueOf(value);
        }
    }

    /**
     * 存储分析步参数
     * @param name 分析步参数名称
     * @param value 分析步参数值
     */
    private void storeStep(String name, Object value) {
        if (name.endsWith("T0")) {
            this.t0 = String.valueOf(value);
        }

        if (name.endsWith("gravity")) {
            this.gravityDirection = String.valueOf(value);
        }

        if (name.endsWith("process")) {
            this.process = String.valueOf(value);
        }
    }

    /**
     * 验证数据是否为整数类型 小数类型 科学计数法类型
     *
     * @param value 数据
     * @return 如果不为上述类型，返回true，否则返回false
     */
    private boolean checkValue(String value) {
        return !value.matches("[+-]?[0-9]+(\\.[0-9]+)?(e[+-]?[0-9]+)?");
    }

    /**
     * 验证数据是否为整数类型
     *
     * @param value 数据
     * @return 如果不为上述类型，返回true，否则返回false
     */
    private boolean checkInteger(String value) {
        return value.matches("[0-9]+");
    }

    /**
     * 赋予默认材料
     */
    private void defaultMaterial() {
        PartVo partVo = materials.get(defaultMaterial);
        AssertUtil.isNull(partVo, CodeEnum.PART_LACK);
        File file = new File(spaceClaimVo.getTxtPath());
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file));) {
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                String[] s = line.split(" ");
                if (!partNames.contains(s[1])) {
                    PartVo newPart = new PartVo();
                    BeanUtils.copyProperties(partVo, newPart);
                    newPart.setBodyname(s[1]);
                    partVos.add(newPart);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}

